<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <title>Android编译系统简要介绍和学习计划 - 老罗的Android之旅
        - 博客频道 - CSDN.NET</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="description" content="在Android源码环境中，我们开发好一个模块后，再写一个Android.mk文件，就可通过m/mm/mmm/make等命令进行编译。此外，通过make命令还可制作各种系统镜像文件，例如system.img、boot.img和recovery.img等。这一切都得益于Android编译系统，它为我们处理了各种依赖关系，以及提供各种有用工具。本文对Android编译系统进行简单介绍以及制定学习计划。" />
    <script src="http://static.blog.csdn.net/scripts/jquery.js" type="text/javascript"></script>
    <script type="text/javascript" src="http://static.blog.csdn.net/scripts/ad.js?v=1.1"></script>
        <!--new top-->
               <link rel="stylesheet" href="http://static.csdn.net/public/common/toolbar/css/index.css">        <!--new top-->

    <link rel="Stylesheet" type="text/css" href="http://static.blog.csdn.net/skin/default/css/style.css?v=1.1" />
    <link id="RSSLink" title="RSS" type="application/rss+xml" rel="alternate" href="/Luoshengyang/rss/list" />
    <link rel="shortcut icon" href="/favicon.ico" />
    <link type="text/css" rel="stylesheet" href="http://static.blog.csdn.net/scripts/SyntaxHighlighter/styles/default.css" />
 

</head>
<body>
    
   
      <!--new top-->
    <script id="toolbar-tpl-scriptId" fixed="true" prod="blog" skin="black" src="http://static.csdn.net/public/common/toolbar/js/html.js" type="text/javascript"></script>
     <!--new top-->
    <div id="container">
        <div id="header">
    <div class="header">
        <div id="blog_title">
            <h2>
                <a href="http://blog.csdn.net/luoshengyang">老罗的Android之旅</a></h2>
            <h3>爱生活，爱Android</h3>
            <div class="clear">
            </div>
        </div>
        <div class="clear">
        </div>
    </div>
</div>
<div id="navigator">
    <div class="navigator_bg">
    </div>
    <div class="navigator">
        <ul>
                <li id="btnContents"><a href="http://blog.csdn.net/luoshengyang?viewmode=contents"><span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_mulu'])">
                    <img src="http://static.blog.csdn.net/images/ico_list.gif">目录视图</span></a></li>
                <li id="btnView"><a href="http://blog.csdn.net/luoshengyang?viewmode=list"><span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_zhaiyao'])">
                    <img src="http://static.blog.csdn.net/images/ico_summary.gif">摘要视图</span></a></li>
                <li id="btnRss"><a href="http://blog.csdn.net/luoshengyang/rss/list"><span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_RSS'])">
                    <img src="http://static.blog.csdn.net/images/ico_rss.gif">订阅</span></a></li>
</ul>
    </div>
</div>
<script type="text/javascript">
    var username = "Luoshengyang";
    var _blogger = username;
    var blog_address = "http://blog.csdn.net/luoshengyang";
    var static_host = "http://static.blog.csdn.net";
    var currentUserName = "";
</script>

        <div id="body">
            <div id="main">
                <div class="main">
<div class="notice tracking-ad" data-mod='popu_3' > 


<a href="http://hero.csdn.net/Question/Details?ID=351&ExamID=346" target="_blank"><font color=blue>英雄会第四届在线编程大赛·线上初赛：带通配符的数
</font></a>

&nbsp;&nbsp;&nbsp;&nbsp;


<a href="http://bbs.csdn.net/topics/390724670"target="_blank">
<font color=red>CSDN社区“三八节”特别活动</font></a>
&nbsp;&nbsp;&nbsp;&nbsp;


<a href="http://www.csdn.net/article/2014-03-06/2818653"target="_blank">
<font color=blue>开发者职业生涯调查之未来</font></a>




</div>                    <link href="http://static.blog.csdn.net/css/comment1.css" type="text/css" rel="stylesheet" />
<link href="http://static.blog.csdn.net/css/style1.css" type="text/css" rel="stylesheet" />
<div id="article_details" class="details">
    <div class="article_title">
    <span class="ico ico_type_Original"></span>
    <h1>
        <span class="link_title"><a href="/luoshengyang/article/details/18466779">
        Android编译系统简要介绍和学习计划
        </a></span>
    </h1>
</div>

    <div class="article_manage">
        <span class="link_categories">
        分类：
            <a href="/Luoshengyang/article/category/838604" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_fenlei']);">Android</a> 
        </span>
    <span class="link_postdate">2014-02-10 01:02</span>
    <span class="link_view" title="阅读次数">5671人阅读</span>
    <span class="link_comments" title="评论次数"><a href="#comments" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">评论</a>(20)</span>
    <span class="link_collect"><a href="javascript:void(0);" onclick="javascript:_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shoucang']);collectArticle('Android编译系统简要介绍和学习计划','18466779');return false;" title="收藏">收藏</a></span>
    <span class="link_report"><a href="#report"  onclick="javascript:_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_jubao']);report(18466779,2);return false;" title="举报">举报</a></span>
    
</div>
<div class="tag2box"><a href='http://www.csdn.net/tag/Android' target=_blank onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">Android</a><a href='http://www.csdn.net/tag/Build' target=_blank onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">Build</a><a href='http://www.csdn.net/tag/System' target=_blank onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">System</a><a href='http://www.csdn.net/tag/make' target=_blank onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">make</a><a href='http://www.csdn.net/tag/mmm' target=_blank onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_tag']);">mmm</a></div>

    
<div id="article_content" class="article_content">
<p>&nbsp; &nbsp; &nbsp; &nbsp; 在Android源码环境中，我们开发好一个模块后，再写一个Android.mk文件，就可通过m/mm/mmm/make等命令进行编译。此外，通过make命令还可制作各种系统镜像文件，例如system.img、boot.img和recovery.img等。这一切都得益于Android编译系统，它为我们处理了各种依赖关系，以及提供各种有用工具。本文对Android编译系统进行简单介绍以及制定学习计划。</p><p align="center"><span style="font-size:14px;color:#CC0000;">老罗的新浪微博：<a target=_blank target="_blank" href="http://weibo.com/shengyangluo">http://weibo.com/shengyangluo</a>，欢迎关注！</span><br /></p><p>&nbsp; &nbsp; &nbsp; &nbsp; 在研究Android编译系统之前，我们首先需要了解Linux系统的make命令。在Linux系统中，我们可以通过make命令来编译代码。Make命令在执行的时候，默认会在当前目录找到一个Makefile文件，然后根据Makefile文件中的指令来对代码进行编译。也就是说，make命令执行的是Makefile文件中的指令。Makefile文件中的指令可以是编译命令，例如gcc，也可以是其它命令，例如Linux系统中的shell命令cp、rm等等。理解这一点非常重要，因为虽然通常我们说make命令是可以编译代码的，但是它实际上可以做任何事情。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 看到这里，有的小伙伴可能会说，在Linux系统中，直接通过shell命令也可以做很多事情啊，它和make命令有什么区别呢？通过前面的介绍可以知道，make命令事实也是通过shell命令来完成任务的，但是它的神奇之处是可以帮我们处理好文件之间的依赖关系。我们通常都有会这样的一个需求，假设有一个文件T，它依赖于另外一个文件D，要求只有当文件D的内容发生变化，才重新生成文件T。这种需求在编译系统中表现得尤其典型，当一个*.c文件include的*.h文件发生变化时，需要重新编译该*.c文件，或者当一个模块A所引用的模块B发生变化时，重新编译模块B。正是由于编译系统中存在这种典型的文件依赖需求，而make命令又是专门用来解决这种文件依赖问题的，因此我们通常认为make命令是用来编译代码的。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; Make命令是怎么知道两个文件之间存在依赖关系，以及当被依赖文件发生变化时如何处理目标文件的呢？答案就在前面提到的Makefile文件。Makefile文件实际上是一个脚本文件，就像普通的shell脚本文件一样，只不过它遵循的是Makefile语法。Makefile文件最基础的功能就是描述文件之间的依赖关系，以及怎么处理这些依赖关系。例如，假设有一个目录文件target，它依赖于文件dependency，并且当文件dependency发生变化时，需要通过command命令来重新生成文件T，这时候我们就可以在Makefile编写以下语句：</p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_1_7867002"  code_snippet_id="181718" snippet_file_name="blog_20140210_1_7867002" name="code" class="plain">target: dependency
&lt;tab&gt;command -o target -i dependency</pre>&nbsp; &nbsp; &nbsp; &nbsp; 我们假设命令command的-o选项指定的是输出文件，而-i选项指定的是输入文件。此外，命令command必须是另起一行，并且以tab键开头。<p></p><p>&nbsp; &nbsp; &nbsp; &nbsp; 这就是最基础也是最主要的Makefile文件语法。当然，Makefile文件还有很多其它的语法，这里不可能一一描述。老罗推荐一本书《GNU make中文手册》，里面非常详细地介绍了make以及Makefile文件语法。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 通常我们在一个源代码工程中，包含有非常多模块，模块之间保持相对独立。我们说相对独立，是指模块之间只在接口上存在依赖，但是在实现上是相全独立的。例如，我们有一个SO模块A，它引用了另一个SO模块B的一个导出函数F。只要函数F的原型不变，那么模块B就可以独立于模块A来实现，而模块A只需要一个包含有函数F原型声明的头文件即可对模块B进行引用。在一个源代码工程中，使得模块之间保持上述的相对独立非常重要，否则的话，当模块多了之后，就会很容易造成混乱。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 当一个源代码工程被划分成很多个相对独立的模块之后，我们就很直觉地想到，为每一个模块都编译写一个Makefile文件，使得它们可以独立编译，然后再在工程的根目录下编写一个Makefile文件来递归执行这些Makefile文件。事实上，这种做法是错误的。正确的做法无论工程有多少个模块，都应该只有一个Makefile文件。注意，即使整个工程只有一个Makefile文件，但是我们仍然是要求对工程进行模块划分，并且需要保持这些模块之间的相对独立性，否则的话，就会同样引发混乱。在整个工程只有一个Makefile文件的情况下，我们要求工程的各个模块拥有自己的Makefile片段。这些Makefile片段统统直接或者间接地通过Makefile语法中的include指令包含在工程的Makefile文件中，然后再进行编译。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 为什么我们要求整个工程只有一个Makefile文件，而不是工程的每一个模块都拥有一个Makefile文件呢？直觉告诉我们，每一个模块都拥有一个Makefile文件就会显得更加独立。事实的确如此，每一个模块都拥有自己的Makefile文件可以使得它更加独立。但是这种方法在处理模块之间的依赖关系时会显得力不从心，导致make命令要么是做得太少（do too little），要么是做得太多（do too much）。Make命令做得太少意味着编译结果不正确，而做得太多意味着编译速度慢。注意，出现这种情况并不是make命令本身的设计有问题，而是因为我们给了它不好的输入，就是所谓的&quot;垃圾进，垃圾出&quot;（Garbage In, Garbage Out）。<br /></p><p>&nbsp; &nbsp; &nbsp; &nbsp; 早在1998年的时候，Peter Miller就发现了为工程的每一个模块都编写一个Makefile文件的种种坏处，并且发表有一篇论文<a target=_blank target="_blank" href="http://aegis.sourceforge.net/auug97.pdf">Recursive Make Considered Harmful</a>。有兴趣的小伙伴可以读一下，写得非常好。这里我们简单从这篇论文摘录一下为什么Recursive Make会导致“do too little”和“do too much”。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 假设我们有一个工程，它的目录结构如下所示：</p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_2_3832012"  code_snippet_id="181718" snippet_file_name="blog_20140210_2_3832012" name="code" class="html">Project
  ----Makefile
  ----ant
       ----Makefile
       ----main.c
  ----bee
       ----Makefile
       ----parse.c
       ----parse.h</pre>&nbsp; &nbsp; &nbsp; 顶层目录的Makefile的内容如下所示：<p></p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_3_9863060"  code_snippet_id="181718" snippet_file_name="blog_20140210_3_9863060" name="code" class="html">MODULES = ant bee
all:
    for dir in $(MODULES); do \
        (cd $$dir; $(MAKE) all); \
    done</pre>&nbsp; &nbsp; &nbsp; ant目录下的Makefile的内容如下所示：<p></p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_4_3211130"  code_snippet_id="181718" snippet_file_name="blog_20140210_4_3211130" name="code" class="html">all: main.o
main.o: main.c ../bee/parse.h
    $(CC) -I../bee -c main.c</pre>&nbsp; &nbsp; &nbsp; &nbsp;通过图1的无回路有向图（DAG）可以清楚看到ant目录的Makefile所描述的文件依赖关系：<p></p><p style="text-align: center;"><img src="http://img.blog.csdn.net/20140131235010343?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHVvc2hlbmd5YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /></p><p style="text-align: center;">图1 ant模块的文件依赖关系图</p><p>&nbsp;<br />&nbsp; &nbsp; &nbsp; &nbsp;bee目录下的Makefile的内容如下所示：</p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_5_2622486"  code_snippet_id="181718" snippet_file_name="blog_20140210_5_2622486" name="code" class="html">OBJ = ../ant/main.o parse.o
all: prog
prog: $(OBJ)
    $(CC) -o $@ $(OBJ)
parse.o: parser.c parse.h
    $(CC) -c parse.c</pre>&nbsp; &nbsp; &nbsp; &nbsp;通过图2的无回路有向图（DAG）可以清楚看到bee目录的Makefile所描述的文件依赖关系：<p></p><p style="text-align: center;"><img src="http://img.blog.csdn.net/20140131235820437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHVvc2hlbmd5YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /></p><p style="text-align: center;">图2 bee模块的文件依赖关系图</p><p>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br />&nbsp; &nbsp; &nbsp; &nbsp;到目前为止，一切都正常，我们在工程根目录下执行make命令，就可以递归对ant和bee模块进行编译，并且最终生成可执行文件prog。<br /></p><p>&nbsp; &nbsp; &nbsp; &nbsp;考虑一个情景，bee目录的parse.h和parse.c文件是通过yacc工具自动生成的，也就是我们在bee/Makefile文件增加以下内容来生成parse.h和parse.c文件：</p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_6_397639"  code_snippet_id="181718" snippet_file_name="blog_20140210_6_397639" name="code" class="html">parse.c parse.h: parse.y
    $(YACC) -d parse.y
    mv y.tab.c parse.c
    mv y.tab.h parse.h</pre>&nbsp; &nbsp; &nbsp; &nbsp;这时候bee模块的文件依赖关系图如图3所示：<p></p><p></p><div style="text-align: center;"><img src="http://img.blog.csdn.net/20140201000826453?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHVvc2hlbmd5YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /></div><span style="text-align: center;"></span><p></p><p style="text-align: center;">图3 修改后的bee模块文件依赖关系图</p><p>&nbsp; &nbsp; &nbsp; &nbsp;这时候如果我们修改了parse.y文件，那么在工程根目录执行make命令时，先会对ant模块进行编译，然后再对bee模块进行编译。由于对ant模块进行编译时，parse.h文件的内容还没有被修改，因此该文件就认为是最新的，于是就不会重新生成main.o文件。接下来对bee模块进行编译时，就会重新生成parse.h和parse.c文件，并且重新生成parse.o文件。很遗憾，在重新生成prog文件时，使用的是过旧的main.o文件，于是就会得到不正确的prog文件。</p><p>&nbsp; &nbsp; &nbsp; &nbsp;产生这个问题的原因就在于ant模块缺乏对parse.h文件的掌控，也就是不知道parse.h文件是如何产生的。如果我们坚持使用这种递归Makefile的方法来编译工程，并且希望解决上述问题，那么有三种方法：</p><p>&nbsp; &nbsp; &nbsp; &nbsp;1. 修改工程目录的Makefile，使得它先对bee模块进行编译，再对ant模块进行编译。然而，这就相当于是要求我们需要明确地指定工程的每一个模块的编译顺序。在一个包含有非常多模块的工程里面，要确定每一个模块的编译顺序是相当困难的。而且当我们新增、修改或者删除模块之后，又需要重新确定各个模块的编译顺序。理想的做法是让make自动地帮我们决定各个模块的编译顺序，这也是我们使用make命令来编译工程的初衷。</p><p>&nbsp; &nbsp; &nbsp; &nbsp;2. 对工程的各个模块进行重复编译，也就是将工程目录的Makefile修改为以下的内容：</p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_7_5381911"  code_snippet_id="181718" snippet_file_name="blog_20140210_7_5381911" name="code" class="html">MODULES = ant bee
all:
    for dir in $(MODULES); do \
        (cd $$dir; $(MAKE) all); \
    done 
    for dir in $(MODULES); do \
        (cd $$dir; $(MAKE) all); \
    done</pre>&nbsp; &nbsp; &nbsp; &nbsp;这里我们只对每一个模块进行了一次重复编译。然而，在一个复杂的工程中，有可能需要多次进行重复编译才能得到正确的编译结果。与前一种方法（do too little）相比，这里明显就是“do too much”。这会使得我们浪费CPU资源，并且拖慢整个工程的编译速度。<p></p><p>&nbsp; &nbsp; &nbsp; &nbsp;3. 修改ant/Makefile文件，增加如下所示的内容：</p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_8_9602033"  code_snippet_id="181718" snippet_file_name="blog_20140210_8_9602033" name="code" class="html">.PHONY: ../bee/parse.h
../bee/parse.h:
    cd ../bee; \
    make clean; \
    make all</pre>&nbsp; &nbsp; &nbsp; &nbsp; 这种方法在每次编译ant模块之前，都先对bee模块进行重新编译，无论它是否需要。与第2种方法相比，这种方法不用对工程的每一个模块都进行重新编译，但是它仍然是“do too much”，因为不管bee模块是否需要重新编译，它都会被重新编译。<p></p><p>&nbsp; &nbsp; &nbsp; &nbsp; 由此可见，上述三种方法，要么是“do too little”，要么是“do too much”，它们虽然都能解决问题，但都不是理想的解决方案。如果我们进一步分析问题的根源，就会发现工程的文件依赖关系是属于工程级别的，也就是它们属于一个整体，而当我们将它们划分成模块级别的时候，就会造成各个模块只看到一部分的文件依赖关系，因此就不能得到正确的编译结果。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 为了保持工程文件依赖关系的整体性，我们就必须使得整个工程只存在一个Makefile。当整个工程只存在一个Makefile时，我们就可以很容易地构造出如图4所示的文件依赖图：</p><p style="text-align: center;"><img src="http://img.blog.csdn.net/20140201005214609?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHVvc2hlbmd5YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /><br /></p><p style="text-align: center;">图4 完整的文件依赖关系图</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 整个工程只有一个Makefile，听起来似乎是一件很疯狂的事情，因为这个Makefile可能会变得无比庞大和复杂。其实不用担心，我们可以按照模块来将这个Makefile划分成一个个Makefile片段（fragement），然后通过Makefile的include指令来将这些Makefile片段组装在一个Makefile中。与递归Makefile相比，每一个模块现在拥有的是一个Makefile片段，而不是一个Makefile文件。这正是Android编译系统的设计思想和原则，也就是说，我们平时所编写的Android.mk编译脚本都只不过是整个Android编译系统的一个Makefile片段。</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 明白了Android编译系统的设计思想和原则之后，我们就可以通过图5来观察一下Android编译系统的整体架构了：</p><p style="text-align: center;"><img src="http://img.blog.csdn.net/20140208110900375?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTHVvc2hlbmd5YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" width="654" /><br /></p><p style="text-align: center;">图5 Android编译系统架构</p><p>&nbsp; &nbsp; &nbsp; &nbsp;在使用Android编译系统之前，我们需要打开一个shell进入到Android源码根目录中，并且在该shell中将build/envsetup.sh脚本文件source进来。脚本文件build/envsetup.sh被source到当前shell的过程中，会在vendor和device两个目录将厂商指定的envsetup.sh也source到当前shell当中，这样就可以获得厂商提供的产品配置信息。此外，脚本文件build/envsetup.sh还提供了以下几个重要的命令来帮助我们编译Android源码：</p><p>&nbsp; &nbsp; &nbsp; &nbsp;1. lunch</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 用来初始化编译环境，例如设置环境变量和指定目标产品型号。Lunch命令在执行的时候，主要做两件事情。第一件事情是设置TARGET_PRODUCT、TARGET_BUILD_VARIANT、TARGET_BUILD_TYPE和TARGET_BUILD_APPS等环境变量，用来指定目标产品类型和编译类型。第二件事情是通过make命令执行build/core/config.mk脚本，并且通过加载另外一个脚本build/core/dumpvar.mk打印出当前的编译环境配置信息。注意，build/core/config.mk和build/core/dumpvar.mk均为Makefile脚本，因此它们可以通过make命令来执行。另外，build/core/config.mk脚本还会加载一个名称为BoradConfig.mk的脚本以及build/core/envsetup.mk脚本来配置目标产品型号的相关信息。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. m</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 相当于是在执行make命令。对整个Android源码进行编译。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. mm</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果是在Android源码根目录下执行，那么就相当于是执行make命令对整个源码进行编译。如果是在Android源码根目录下的某一个子目录执行，那么就在会在从该子目录开始，一直往上一个目录直至到根目录，寻找是否存在一个Android.mk文件。如果存在的话，那么就通过make命令对该Android.mk文件描述的模块进行编译。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4. mmm</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后面可以跟一个或者若干个目录。如果指定了多个目录，那么目录之间以空格分隔，并且每一个目录下都必须存在一个Android,mk文件。如果没有在目录后面通过冒号指定模块名称，那么在Android.mk文件中描述的所有模块都会被编译，否则只有指定的模块会被编译。如果需要同时指定多个模块，那么这些模块名称必须以逗号分隔。它的语法如下所示：</p><p></p><pre code_snippet_id="181718" snippet_file_name="blog_20140210_9_9046409"  code_snippet_id="181718" snippet_file_name="blog_20140210_9_9046409" name="code" class="html">mmm &lt;dir-1&gt; &lt;dir-2&gt; ... &lt;dir-N&gt;[:module-1,module-2,...,module-M]</pre>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该命令会通过make命令来执行Android源码根目录下的Makefile文件，该Makefile文件又会将build/core/main.mk加载进来。文件build/core/main.mk在加载的过程中，还会加载以下几个主要的文件：<p></p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1). build/core/config.mk</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该文件根据lunch命令所配置的产品信息在build/target/board、vendor或者device目录中找到对应的BoradConfig.mk文件，以及通过加载build/core/product_config.mk文件在build/target/product、vendor或者device目录中找到对应的AndroidProducts.mk文件，来进一步对编译环境进行配置，以便接下来编译指定模块时可以获得必要的信息。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2). build/core/definitions.mk</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该文件定义了在编译过程需要调用到的各种自定义函数。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3). 指定的Android.mk</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这些指定的Android.mk环境是由mmm命令通过环境变量ONE_SHOT_MAKEFILE传递给build/core/main.mk文件使用的。这些Android.mk文件一般还会通过环境变量BUILD_PACKAGE、BUILD_JAVA_LIBRARY、BUILD_STATIC_JAVA_LIBRARY、BUILD_SHARED_LIBRARY、BUILD_STATIC_LIBRARY、BUILD_EXECUTABLE和BUILD_PREBUILT将build/core/package.mk、build/core/java_library.mk、build/core/static_java_library.mk、build/core/shared_library.mk、build/core/static_library.mk、build/core/executable.mk和build/core/prebuilt.mk等编译片段模板文件加载进来，来表示要编译是APK、Java库、Linux动态库/静态库/可执行文件或者预先编译好的文件等等。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (4). build/core/Makefile</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该文件包含了用来制作system.img、ramdisk.img、boot.img和recovery.img等镜像文件的脚本。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在接下来的一系列文章中，我们将按照以下情景来进一步分析Android的编译系统：</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. <a target=_blank target="_blank" href="http://blog.csdn.net/luoshengyang/article/details/18928789">Android编译系统的环境初始化过程</a>；</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. <a target=_blank href="http://blog.csdn.net/luoshengyang/article/details/19023609">模块编译命令mmm的执行过程</a>；</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. Android镜像文件的制作过程；</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 希望通过这三个情景的分析，使得我们对Android的编译系统有一个深刻的认识，以提高我们的Android系统开发效率，敬请关注！更多信息可以关注老罗的新浪微博：<a target=_blank target="_blank" href="http://weibo.com/shengyangluo">http://weibo.com/shengyangluo</a><br /></p>
</div>



<!-- Baidu Button BEGIN -->
<div id="bdshare" class="bdshare_t bds_tools get-codes-bdshare" style="float: right;">
<a class="bds_qzone"></a>
<a class="bds_tsina"></a>
<a class="bds_tqq"></a>
<a class="bds_renren"></a>
<a class="bds_t163"></a>
<span class="bds_more">更多</span>
<a class="shareCount"></a>
</div>
<!-- Baidu Button END -->


<!--192.168.100.33-->
<div class="article_next_prev">
            <li class="prev_article"><span>上一篇：</span><a href="/luoshengyang/article/details/18195205" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shangyipian'])">Android源代码仓库及其管理工具Repo分析</a></li>
            <li class="next_article"><span>下一篇：</span><a href="/luoshengyang/article/details/18928789" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_xiayipian'])">Android编译系统环境初始化过程分析</a></li>
</div>

<!-- Baidu Button BEGIN -->
<script type="text/javascript" id="bdshare_js" data="type=tools&amp;uid=1536434" ></script>
<script type="text/javascript" id="bdshell_js"></script>
<script type="text/javascript">
    document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000)
</script>
<!-- Baidu Button END -->

        <div id="digg" ArticleId="18466779">
            <dl id="btnDigg" class="digg digg_disable">
                <dt onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_ding'])">顶</dt>
                <dd>11</dd>
            </dl>
            <dl id="btnBury" class="digg digg_disable">
                <dt onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_cai'])">踩</dt>
                <dd>0</dd>
            </dl>
        </div>
</div>
      <dl class="blog-associat-tag">
        <dt>相关主题推荐</dt>
        <dd>
                <a href="http://www.csdn.net/tag/android" target="_blank">android</a> 
                <a href="http://www.csdn.net/tag/新浪微博" target="_blank">新浪微博</a> 
                <a href="http://www.csdn.net/tag/系统架构" target="_blank">系统架构</a> 
                <a href="http://www.csdn.net/tag/解决方案" target="_blank">解决方案</a> 
                <a href="http://www.csdn.net/tag/源代码" target="_blank">源代码</a> 
        </dd>
    </dl> 
    <dl class="blog-ass-articl">
        <dt>相关博文推荐</dt>
            <dd>
                <a href="http://blog.csdn.net/ruxming/article/details/21381193" title="[PAAS] Heroku git clone 问题解决" target="_blank">[PAAS] Heroku git cl...</a></dd>
            <dd>
                <a href="http://blog.csdn.net/u012515223/article/details/21379067" title="Android - Compass(罗盘) 详解" target="_blank">Android - Compass(罗盘...</a></dd>
            <dd>
                <a href="http://blog.csdn.net/zpj779878443/article/details/21373099" title="android布局------TableLayout(表格布局)详解" target="_blank">android布局------Table...</a></dd>
            <dd>
                <a href="http://blog.csdn.net/vaecer/article/details/21378463" title="Android中的Bitmap、Drawable、图像简单处理" target="_blank">Android中的Bitmap、Draw...</a></dd>
            <dd>
                <a href="http://blog.csdn.net/huanongjingchao/article/details/21375865" title="通过联系人号码获取联系人的姓名（android开发）" target="_blank">通过联系人号码获取联系人的姓名（andr...</a></dd>
            <dd>
                <a href="http://blog.csdn.net/QQ289665044/article/details/21376391" title="简单又好看的按钮,扁平化按钮." target="_blank">简单又好看的按钮,扁平化按钮.</a></dd>
            <dd>
                <a href="http://blog.csdn.net/wo17796452/article/details/21374851" title="Android 全局Activity动画设置" target="_blank">Android 全局Activity动画...</a></dd>
            <dd>
                <a href="http://blog.csdn.net/sam_linux/article/details/21374381" title="apis.view 之 Animation，AutoComplete" target="_blank">apis.view 之 Animatio...</a></dd>
    </dl>

    <div id="ad_cen">
        <script type="text/javascript">            BAIDU_CLB_SLOT_ID = "117306";</script>
        <script type="text/javascript" src="http://cbjs.baidu.com/js/o.js"></script>
    </div>
    <script type="text/javascript">
        //new Ad(4, 'ad_cen');
    </script>
<div id="comment_title" class="panel_head">
    查看评论<a name="comments"></a></div>
<div id="comment_list">
</div>
<div id="comment_bar">
</div>
<div id="comment_form">
</div>
<div class="announce">
    * 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场<a name="reply"></a><a name="quote"></a></div>
<script type="text/javascript">
    var fileName = '18466779';
    var commentscount = 20;
    var islock = false
</script>
<script type="text/javascript" src="http://static.blog.csdn.net/scripts/comment.js"></script>
    <div id="ad_bot">
    </div>
    <script type="text/javascript">
    new Ad(5, 'ad_bot');
    </script>
<div id="report_dialog">
</div>
<div id="d-top" style="display: none;">
    <a id="d-top-a" href="#" title="回到顶部" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_huidaodingbu'])">
        <img src="http://static.blog.csdn.net/images/top.png" alt="TOP" /></a>
</div>
<script type="text/javascript">
    $(function ()
    {
        var d_top = $('#d-top');
        document.onscroll = function ()
        {
            var scrTop = (document.body.scrollTop || document.documentElement.scrollTop);
            if (scrTop > 500)
            {
                d_top.show();
            } else
            {
                d_top.hide();
            }
        }
        $('#d-top-a').click(function ()
        {
            scrollTo(0, 0);
            this.blur();
            return false;
        });
    });
  
</script>
<style type="text/css">
    .tag_list
    {
        background: none repeat scroll 0 0 #FFFFFF;
        border: 1px solid #D7CBC1;
        color: #000000;
        font-size: 12px;
        line-height: 20px;
        list-style: none outside none;
        margin: 10px 2% 0 1%;
        padding: 1px;
    }
    .tag_list h5
    {
        background: none repeat scroll 0 0 #E0DBD3;
        color: #47381C;
        font-size: 12px;
        height: 24px;
        line-height: 24px;
        padding: 0 5px;
        margin: 0;
    }
    .tag_list h5 a
    {
        color: #47381C;
    }
    .classify
    {
        margin: 10px 0;
        padding: 4px 12px 8px;
    }
    .classify a
    {
        margin-right: 20px;
        white-space: nowrap;
    }
</style>
<div class="tag_list">
    <h5>
        <a href="http://www.csdn.net/tag/" target="_blank">核心技术类目</a></h5>
    <div class="classify">
<a title="全部主题" href="http://www.csdn.net/tag" target="_blank" onclick="LogClickCount(this,336);">全部主题</a>
<a title="Java" href="http://www.csdn.net/tag/Java" target="_blank" onclick="LogClickCount(this,336);">Java</a>
<a title="VPN" href="http://www.csdn.net/tag/vpn" target="_blank" onclick="LogClickCount(this,336);">VPN</a>
<a title="Android" href="http://www.csdn.net/tag/android" target="_blank" onclick="LogClickCount(this,336);">Android</a>
<a title="iOS" href="http://www.csdn.net/tag/ios" target="_blank" onclick="LogClickCount(this,336);">iOS</a>
<a title="ERP" href="http://www.csdn.net/tag/erp" target="_blank" onclick="LogClickCount(this,336);">ERP</a>
<a title="IE10" href="http://www.csdn.net/tag/ie10" target="_blank" onclick="LogClickCount(this,336);">IE10</a>
<a title="Eclipse" href="http://www.csdn.net/tag/eclipse" target="_blank" onclick="LogClickCount(this,336);">Eclipse</a>
<a title="CRM" href="http://www.csdn.net/tag/crm" target="_blank" onclick="LogClickCount(this,336);">CRM</a>
<a title="JavaScript" href="http://www.csdn.net/tag/javascript" target="_blank" onclick="LogClickCount(this,336);">JavaScript</a>
<a title="Ubuntu" href="http://www.csdn.net/tag/ubuntu" target="_blank" onclick="LogClickCount(this,336);">Ubuntu</a>
<a title="NFC" href="http://www.csdn.net/tag/nfc" target="_blank" onclick="LogClickCount(this,336);">NFC</a>
<a title="WAP" href="http://www.csdn.net/tag/wap" target="_blank" onclick="LogClickCount(this,336);">WAP</a>
<a title="jQuery" href="http://www.csdn.net/tag/jquery" target="_blank" onclick="LogClickCount(this,336);">jQuery</a>
<a title="数据库" href="http://www.csdn.net/tag/数据库" target="_blank" onclick="LogClickCount(this,336);">数据库</a>
<a title="BI" href="http://www.csdn.net/tag/bi" target="_blank" onclick="LogClickCount(this,336);">BI</a>
<a title="HTML5" href="http://www.csdn.net/tag/html5" target="_blank" onclick="LogClickCount(this,336);">HTML5</a>
<a title="Spring" href="http://www.csdn.net/tag/spring" target="_blank" onclick="LogClickCount(this,336);">Spring</a>
<a title="Apache" href="http://www.csdn.net/tag/apache" target="_blank" onclick="LogClickCount(this,336);">Apache</a>
<a title="Hadoop" href="http://www.csdn.net/tag/hadoop" target="_blank" onclick="LogClickCount(this,336);">Hadoop</a>
<a title=".NET" href="http://www.csdn.net/tag/.net" target="_blank" onclick="LogClickCount(this,336);">.NET</a>
<a title="API" href="http://www.csdn.net/tag/api" target="_blank" onclick="LogClickCount(this,336);">API</a>
<a title="HTML" href="http://www.csdn.net/tag/html" target="_blank" onclick="LogClickCount(this,336);">HTML</a>
<a title="SDK" href="http://www.csdn.net/tag/sdk" target="_blank" onclick="LogClickCount(this,336);">SDK</a>
<a title="IIS" href="http://www.csdn.net/tag/iis" target="_blank" onclick="LogClickCount(this,336);">IIS</a>
<a title="Fedora" href="http://www.csdn.net/tag/fedora" target="_blank" onclick="LogClickCount(this,336);">Fedora</a>
<a title="XML" href="http://www.csdn.net/tag/xml" target="_blank" onclick="LogClickCount(this,336);">XML</a>
<a title="LBS" href="http://www.csdn.net/tag/lbs" target="_blank" onclick="LogClickCount(this,336);">LBS</a>
<a title="Unity" href="http://www.csdn.net/tag/unity" target="_blank" onclick="LogClickCount(this,336);">Unity</a>
<a title="Splashtop" href="http://www.csdn.net/tag/splashtop" target="_blank" onclick="LogClickCount(this,336);">Splashtop</a>
<a title="UML" href="http://www.csdn.net/tag/uml" target="_blank" onclick="LogClickCount(this,336);">UML</a>
<a title="components" href="http://www.csdn.net/tag/components" target="_blank" onclick="LogClickCount(this,336);">components</a>
<a title="Windows Mobile" href="http://www.csdn.net/tag/windowsmobile" target="_blank" onclick="LogClickCount(this,336);">Windows Mobile</a>
<a title="Rails" href="http://www.csdn.net/tag/rails" target="_blank" onclick="LogClickCount(this,336);">Rails</a>
<a title="QEMU" href="http://www.csdn.net/tag/qemu" target="_blank" onclick="LogClickCount(this,336);">QEMU</a>
<a title="KDE" href="http://www.csdn.net/tag/kde" target="_blank" onclick="LogClickCount(this,336);">KDE</a>
<a title="Cassandra" href="http://www.csdn.net/tag/cassandra" target="_blank" onclick="LogClickCount(this,336);">Cassandra</a>
<a title="CloudStack" href="http://www.csdn.net/tag/cloudstack" target="_blank" onclick="LogClickCount(this,336);">CloudStack</a>
<a title="FTC" href="http://www.csdn.net/tag/ftc" target="_blank" onclick="LogClickCount(this,336);">FTC</a>
<a title="coremail" href="http://www.csdn.net/tag/coremail" target="_blank" onclick="LogClickCount(this,336);">coremail</a>
<a title="OPhone " href="http://www.csdn.net/tag/ophone " target="_blank" onclick="LogClickCount(this,336);">OPhone </a>
<a title="CouchBase" href="http://www.csdn.net/tag/couchbase" target="_blank" onclick="LogClickCount(this,336);">CouchBase</a>
<a title="云计算" href="http://www.csdn.net/tag/云计算" target="_blank" onclick="LogClickCount(this,336);">云计算</a>
<a title="iOS6" href="http://www.csdn.net/tag/iOS6" target="_blank" onclick="LogClickCount(this,336);">iOS6</a>
<a title="Rackspace " href="http://www.csdn.net/tag/rackspace " target="_blank" onclick="LogClickCount(this,336);">Rackspace </a>
<a title="Web App" href="http://www.csdn.net/tag/webapp" target="_blank" onclick="LogClickCount(this,336);">Web App</a>
<a title="SpringSide" href="http://www.csdn.net/tag/springside" target="_blank" onclick="LogClickCount(this,336);">SpringSide</a>
<a title="Maemo" href="http://www.csdn.net/tag/maemo" target="_blank" onclick="LogClickCount(this,336);">Maemo</a>
<a title="Compuware" href="http://www.csdn.net/tag/compuware" target="_blank" onclick="LogClickCount(this,336);">Compuware</a>
<a title="大数据" href="http://www.csdn.net/tag/大数据" target="_blank" onclick="LogClickCount(this,336);">大数据</a>
<a title="aptech" href="http://www.csdn.net/tag/aptech" target="_blank" onclick="LogClickCount(this,336);">aptech</a>
<a title="Perl" href="http://www.csdn.net/tag/perl" target="_blank" onclick="LogClickCount(this,336);">Perl</a>
<a title="Tornado" href="http://www.csdn.net/tag/tornado" target="_blank" onclick="LogClickCount(this,336);">Tornado</a>
<a title="Ruby" href="http://www.csdn.net/tag/ruby" target="_blank" onclick="LogClickCount(this,336);">Ruby</a>
<a title="Hibernate" href="http://www.csdn.net/hibernate" target="_blank" onclick="LogClickCount(this,336);">Hibernate</a>
<a title="ThinkPHP" href="http://www.csdn.net/tag/thinkphp" target="_blank" onclick="LogClickCount(this,336);">ThinkPHP</a>
<a title="Spark" href="http://www.csdn.net/tag/spark" target="_blank" onclick="LogClickCount(this,336);">Spark</a>
<a title="HBase" href="http://www.csdn.net/tag/hbase" target="_blank" onclick="LogClickCount(this,336);">HBase</a>
<a title="Pure" href="http://www.csdn.net/tag/pure" target="_blank" onclick="LogClickCount(this,336);">Pure</a>
<a title="Solr" href="http://www.csdn.net/tag/solr" target="_blank" onclick="LogClickCount(this,336);">Solr</a>
<a title="Angular" href="http://www.csdn.net/tag/angular" target="_blank" onclick="LogClickCount(this,336);">Angular</a>
<a title="Cloud Foundry" href="http://www.csdn.net/tag/cloudfoundry" target="_blank" onclick="LogClickCount(this,336);">Cloud Foundry</a>
<a title="Redis" href="http://www.csdn.net/tag/redis" target="_blank" onclick="LogClickCount(this,336);">Redis</a>
<a title="Scala" href="http://www.csdn.net/tag/scala" target="_blank" onclick="LogClickCount(this,336);">Scala</a>
<a title="Django" href="http://www.csdn.net/tag/django" target="_blank" onclick="LogClickCount(this,336);">Django</a>
<a title="Bootstrap" href="http://www.csdn.net/tag/bootstrap" target="_blank" onclick="LogClickCount(this,336);">Bootstrap</a>
    </div>
</div>

                    <div class="clear">
                    </div>
                </div>
            </div>
            <div id="side">
    <div class="side">
<div id="panel_Profile" class="panel">
<ul class="panel_head"><span>个人资料</span></ul>
<ul class="panel_body profile">
<div id="blog_userface">
    <a href="http://my.csdn.net/Luoshengyang" target="_blank">
    <img src="http://avatar.csdn.net/5/6/E/1_luoshengyang.jpg" title="访问我的空间" style="max-width:90%"/>
    </a>
    <br />
    <span><a href="http://my.csdn.net/Luoshengyang" class="user_name" target="_blank">Luoshengyang</a></span>
</div>
<div class="interact">
<a href="javascript:void(0);" class="attent" id="span_add_follow" title="[加关注]" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_guanzhu'])"></a>
<a href="javascript:void(0);" class="letter" onclick="loginto(1)" title="[发私信]" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_sixin'])"></a>
</div>
<div id="blog_medal">
        <div class="ico_expert" title="CSDN认证专家"></div>
</div>
<ul id="blog_rank">
    <li>访问：<span>3178993次</span></li>
    <li>积分：<span>16488分</span></li>
    <li>排名：<span>第128名</span></li>
</ul>
<ul id="blog_statistics">
    <li>原创：<span>100篇</span></li>
    <li>转载：<span>0篇</span></li>
    <li>译文：<span>0篇</span></li>
    <li>评论：<span>5226条</span></li>
</ul>
</ul>
</div>


<div id="custom_column_6567056" class="panel">
<ul class="panel_head"><span>博客公告</span></ul>
<ul class="panel_body">
<b><font color="red" size="2">本博客所有文章均为原创，欢迎交流，欢迎转载；转载请勿篡改内容，并且注明出处，禁止用于商业目的，谢谢！</font></b>
</ul>
</div><div id="custom_column_21664874" class="panel">
<ul class="panel_head"><span>图书信息</span></ul>
<ul class="panel_body">
<font color="red"><b>书名：</b></font>
<p>《Android系统源代码情景分析》</p>

<p><a href="http://wenku.it168.com/d_000574719.shtml" target="_blank">试读请点击</a></p>

<p><font color="red"><b>出版社：</b></font></p>
<p>电子工业出版社</p>

<p><font color="red"><b>网店：</b></font></p>

<p>1. <a href="http://product.dangdang.com/product.aspx?product_id=22884086" target="_blank">当当网（满100减20，满200减50）</a></p><p></p>

<p>2. <a href="http://book.360buy.com/11104739.html" target="_blank">京东网（满99减20）</a></p><p></p>

<p>3. <a href="http://www.amazon.cn/Android%E7%B3%BB%E7%BB%9F%E6%BA%90%E4%BB%A3%E7%A0%81%E6%83%85%E6%99%AF%E5%88%86%E6%9E%90-%E7%BD%97%E5%8D%87%E9%98%B3/dp/B009OLU8EE" target="_blank">亚马逊网（满100减20，满200减50）</a></p><p></p>

<p>4. <a href="http://product.china-pub.com/3684413" target="_blank">互动出版网</a></p><p></p>

<p>5. <a href="http://www.suning.com/emall/prd_10052_22001_-7_3435777_.html" target="_blank">苏宁易购网</a></p><p></p>

<p><a href="http://s.etao.com/search?spm=1002.8.1.1386.g76Rk3&amp;q=Android%CF%B5%CD%B3%D4%B4%B4%FA%C2%EB%C7%E9%BE%B0%B7%D6%CE%F6&amp;style=list&amp;initiative_id=etao_20121011&amp;pn=1&amp;sort=sale-desc" target="_blank">比一比谁更实惠</a></p>

<p><font color="red"><b>号外：</b></font></p>

<p>本书繁体版已经成功输出到台湾</p>

<p></p>
</ul>
</div><div id="custom_column_21603386" class="panel">
<ul class="panel_head"><span>联系方式</span></ul>
<ul class="panel_body">
<font color="red"><b>新浪微博：</b></font>
<p><a href="http://weibo.com/shengyangluo" target="_blank"><font color="red"><b>http://weibo.com/shengyangluo</b></font></a></p><p></p>

<font color="red"><b>QQ交流群：</b></font>
<p><b><font color="red">130112760</font></b>（1000人群，已满）</p>
<p><b><font color="red">248749286</font></b>（1000人群，已满）</p>
<p><b><font color="red">204155322</font></b>（500人群，未满）</p>
<p><b><font color="red">278558417</font></b>（500人群，已满）</p>
<p><b><font color="red">303165655</font></b>（500人群，已满）</p>
<p>PS：请勿同时加入多个群，一经发现，永久封号，谢谢！</p>
</ul>
</div><div id="panel_Category" class="panel">
    <ul class="panel_head"><span>博客专栏</span></ul>
    <ul class="panel_body" id="sp_column">
    <table cellpadding="0" cellspacing="0"><tr>
    <td style="padding:10px 10px 0 0;">
    <a href="http://blog.csdn.net/column/details/androidluo.html" target="_blank"><img src="http://avatar.csdn.net/blogpic/20111107095438958.jpg" style="width:75px;height:75px;" /></a>
    </td>
    <td style="padding:10px 0; vertical-align:top;">
    <a href="http://blog.csdn.net/column/details/androidluo.html" target="_blank">老罗的Android之旅</a>
    <p>文章：100篇</p>
    <span>阅读：3182886</span>
    </td>
    </tr></table>
    </ul>
</div><div id="hotarticls" class="panel">
<ul class="panel_head"><span>阅读排行</span></ul>
<ul class="panel_body itemlist">
<li>
<a href="/luoshengyang/article/details/6559955" title="在Ubuntu上下载、编译和安装Android最新源代码">在Ubuntu上下载、编译和安装Android最新源代码</a><span>(109863)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6618363" title="Android进程间通信（IPC）机制Binder简要介绍和学习计划">Android进程间通信（IPC）机制Binder简要介绍和学习计划</a><span>(95847)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6689748" title="Android应用程序启动过程源代码分析">Android应用程序启动过程源代码分析</a><span>(81231)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6568411" title="在Ubuntu上为Android系统编写Linux内核驱动程序">在Ubuntu上为Android系统编写Linux内核驱动程序</a><span>(78858)</span>
</li>
<li>
<a href="/luoshengyang/article/details/8923485" title="那两年炼就的Android内功修养">那两年炼就的Android内功修养</a><span>(77485)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6567257" title="Android硬件抽象层（HAL）概要介绍和学习计划">Android硬件抽象层（HAL）概要介绍和学习计划</a><span>(72810)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6564592" title="在Ubuntu上下载、编译和安装Android最新内核源代码（Linux Kernel）">在Ubuntu上下载、编译和安装Android最新内核源代码（Linux Kernel）</a><span>(66905)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6557518" title="Android学习启动篇">Android学习启动篇</a><span>(59276)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6566662" title="如何单独编译Android源代码中的模块">如何单独编译Android源代码中的模块</a><span>(58230)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6575988" title="在Ubuntu为Android硬件抽象层（HAL）模块编写JNI方法提供Java访问硬件服务接口">在Ubuntu为Android硬件抽象层（HAL）模块编写JNI方法提供Java访问硬件服务接口</a><span>(56883)</span>
</li>
</ul>
</div>
<div id="hotarticls2" class="panel">
<ul class="panel_head"><span>评论排行</span></ul>
<ul class="panel_body itemlist">
<li>
<a href="/luoshengyang/article/details/6689748" title="Android应用程序启动过程源代码分析">Android应用程序启动过程源代码分析</a><span>(322)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6559955" title="在Ubuntu上下载、编译和安装Android最新源代码">在Ubuntu上下载、编译和安装Android最新源代码</a><span>(238)</span>
</li>
<li>
<a href="/luoshengyang/article/details/8116866" title="《Android系统源代码情景分析》一书勘误">《Android系统源代码情景分析》一书勘误</a><span>(209)</span>
</li>
<li>
<a href="/luoshengyang/article/details/8923485" title="那两年炼就的Android内功修养">那两年炼就的Android内功修养</a><span>(183)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6882903" title="Android应用程序键盘（Keyboard）消息处理机制分析">Android应用程序键盘（Keyboard）消息处理机制分析</a><span>(182)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6580267" title="在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务">在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务</a><span>(170)</span>
</li>
<li>
<a href="/luoshengyang/article/details/7409491" title="Android博客文章整理">Android博客文章整理</a><span>(167)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6568411" title="在Ubuntu上为Android系统编写Linux内核驱动程序">在Ubuntu上为Android系统编写Linux内核驱动程序</a><span>(151)</span>
</li>
<li>
<a href="/luoshengyang/article/details/8452527" title="2012年的Android之旅：梦想、学习、坚持、自信、淡定">2012年的Android之旅：梦想、学习、坚持、自信、淡定</a><span>(139)</span>
</li>
<li>
<a href="/luoshengyang/article/details/6564592" title="在Ubuntu上下载、编译和安装Android最新内核源代码（Linux Kernel）">在Ubuntu上下载、编译和安装Android最新内核源代码（Linux Kernel）</a><span>(136)</span>
</li>
</ul>
</div>
<div id="newcomments" class="panel">
<ul class="panel_head"><span>最新评论</span></ul>
<ul class="panel_body itemlist">
    <li>
    <a href="/Luoshengyang/article/details/6557518#comments">Android学习启动篇</a>
    <p style="margin:0px;"><a href="/zywisdoml" class="user_name">zywisdoml</a>:
@u013060190:闻道有先后，术业有专攻，与君共勉！
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/6575988#comments">在Ubuntu为Android硬件抽象层（HAL）模块编写JNI方法提供Java访问硬件服务接口</a>
    <p style="margin:0px;"><a href="/kunleaaa" class="user_name">kunleaaa</a>:
罗老师 你好 如果我在 /Android/frameworks/base/services/jni ...
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/6817933#comments">Android应用程序消息处理机制（Looper、Handler）分析</a>
    <p style="margin:0px;"><a href="/jake1121" class="user_name">jake1121</a>:
顶，老罗写得很用心。
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/6567257#comments">Android硬件抽象层（HAL）概要介绍和学习计划</a>
    <p style="margin:0px;"><a href="/hanmengaidudu" class="user_name">hanmengaidudu</a>:
@linhui568:adb logcat查看系统启动的log，应该是某个位置出错了，贴log出来再...
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/6567257#comments">Android硬件抽象层（HAL）概要介绍和学习计划</a>
    <p style="margin:0px;"><a href="/hanmengaidudu" class="user_name">hanmengaidudu</a>:
@ljbphoebe:你看这个错误的上一行，应该是有个framework目录下面的jar包的问题，把...
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/6575988#comments">在Ubuntu为Android硬件抽象层（HAL）模块编写JNI方法提供Java访问硬件服务接口</a>
    <p style="margin:0px;"><a href="/hanmengaidudu" class="user_name">hanmengaidudu</a>:
@newsten:修改完ueventd.rc，必须重新下载ramdisk.img
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/6575988#comments">在Ubuntu为Android硬件抽象层（HAL）模块编写JNI方法提供Java访问硬件服务接口</a>
    <p style="margin:0px;"><a href="/hanmengaidudu" class="user_name">hanmengaidudu</a>:
@xinxianzhongndsc:再往上面截点logcat，肯定是哪个库或者jar包有问题，重新加...
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/8116866#comments">《Android系统源代码情景分析》一书勘误</a>
    <p style="margin:0px;"><a href="/l975764577" class="user_name">l975764577</a>:
你好，我在64Ubtunu想java1.7版本想编译android源码他给我提示只能使用java1....
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/12957169#comments">《老罗的Android之旅》导读PPT</a>
    <p style="margin:0px;"><a href="/kedongjun" class="user_name">kedongjun</a>:
看得一头雾水，不知所云。。。
    </p>
    </li>
    <li>
    <a href="/Luoshengyang/article/details/8923485#comments">那两年炼就的Android内功修养</a>
    <p style="margin:0px;"><a href="/itom1900" class="user_name">itom1900</a>:
老罗写的书确实很好，在分析android系统级别分析的非常好，我感觉写书想买的好卖钱也得走城乡结合部...
    </p>
    </li>
</ul>
</div>
    </div>
    <div class="clear">
    </div>
</div>

            <div class="clear">
            </div>
        </div>
        

<script type="text/javascript" src="http://static.blog.csdn.net/scripts/newblog.min.js"></script>
<script type="text/javascript" src="http://medal.blog.csdn.net/showblogmedal.ashx?blogid=1134701"></script>
<script type="text/javascript">
    document.write('<script type="text/javascript" src="http://csdnimg.cn/pubfooter/js/publib_footer.js?' + Math.floor(new Date() / 120000).toString(36) + '="></' + 'script>');
</script>
    <script type="text/javascript" src="http://passport.csdn.net/content/loginbox/login.js"></script>
<script type="text/javascript">document.write("<img src=http://counter.csdn.net/pv.aspx?id=24 border=0 width=0 height=0>");</script>
<script type="text/javascript" src="http://www.csdn.net/ui/scripts/Csdn/counter.js"></script>
<script type="text/javascript" src="http://ad.csdn.net/scripts/ad-blog.js"></script>
<script type="text/javascript" src="http://zz.csdn.net/js/count.js"></script>
<script type="text/javascript">
    $(function () {
        function __get_code_toolbar(snippet_id) {
            return $("<a href='https://code.csdn.net/snippets/"
                    + snippet_id
                    + "' target='_blank' title='在CODE上查看代码片' style='text-indent:0;'><img src='https://code.csdn.net/assets/CODE_ico.png' width=12 height=12 alt='在CODE上查看代码片' style='position:relative;top:1px;left:2px;'/></a>"
                    + "<a href='https://code.csdn.net/snippets/"
                    + snippet_id
                    + "/fork' target='_blank' title='派生到我的代码片'  style='text-indent:0;'><img src='https://code.csdn.net/assets/ico_fork.svg' width=12 height=12 alt='派生到我的代码片' style='position:relative;top:2px;left:2px;'/></a>");
        }
        
        $("[code_snippet_id]").each(function () {
            __s_id = $(this).attr("code_snippet_id");
            if (__s_id != null && __s_id != "" && __s_id != 0 && parseInt(__s_id) > 70020) {
                __code_tool = __get_code_toolbar(__s_id);
                $(this).prev().find(".tools").append(__code_tool);
            }
        });
    });
</script>

    </div>
      <!--new top-->
    
    <script id="csdn-toolbar-id" btnId="header_notice_num" wrapId="note1" count="5" subCount="5" type="text/javascript" src="http://static.csdn.net/public/common/toolbar/js/toolbar.js"></script>     <!--new top-->
</body>
</html>
